use anyhow::Result;

use std::fmt;

use crate::utils::{cookie_store::CookieStore, url_pared::UrlPared};

#[derive(Debug, Clone)]
pub enum BodyType {
    Unknown,
    Json,
    Form,
    Multipart,
    Binary,
}
#[derive(Debug, Clone)]
pub enum MethodType {
    GET,
    POST,
}

impl fmt::Display for MethodType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s = match self {
            MethodType::GET => "get",
            MethodType::POST => "post",
            _ => "get",
        };
        write!(f, "{}", s)
    }
}

/// 解析curl字符串命令
#[derive(Debug, Clone)]
pub struct CurlCommand {
    pub url: String,
    pub method: String,
    pub cookie: Option<String>,
    pub headers: Vec<(String, String)>,

    pub body: Option<String>,
}

impl CurlCommand {
    /// 从curl字符串里解析curl结构
    pub fn from_str(curl_str: &str) -> Result<Self, String> {
        if !curl_str.trim_start().starts_with("curl ") {
            return Err("不是有效的 curl 命令".to_string());
        }

        // 使用find再来解析一遍
        let split_params = curl_str
            .split(" \\")
            .filter_map(|s| {
                let trimmed = s.trim();

                let parts: Vec<&str> = trimmed.splitn(2, ' ').collect();

                if parts.len() != 2 {
                    return None;
                }

                let key = parts[0].to_string();

                let val = parts[1].trim();
                let start = val.find('\'')?;
                let end = val.rfind('\'')?;
                if end <= start {
                    return None;
                }

                let content = &val[start + 1..end];
                Some((key, content.to_string()))
            })
            .collect::<Vec<(String, String)>>();

        // ✅ 转换为 ["-H", "Header: value", ...] 的 Vec<String>
        let args = split_params
            .into_iter()
            .flat_map(|(k, v)| vec![k, v])
            .collect::<Vec<String>>();

        let mut url = String::new();
        let mut method = "GET".to_string();
        let mut cookie = None;
        let mut headers = Vec::new();
        let mut body = None;

        let mut iter = args.into_iter().peekable();
        while let Some(arg) = iter.next() {
            match arg.as_str() {
                "curl" => continue,
                "-X" | "--request" => {
                    if let Some(val) = iter.next() {
                        method = val;
                    }
                }
                "-H" | "--header" => {
                    if let Some(header_str) = iter.next() {
                        if let Some((k, v)) = header_str.split_once(':') {
                            headers.push((k.trim().to_string(), v.trim().to_string()));
                        }
                    }
                }
                "-d" | "--data" | "--data-raw" | "--data-binary" => {
                    if let Some(d) = iter.next() {
                        println!("---{d}");
                        body = Some(d.replace("$'", "'"));
                    }
                }
                "-b" | "--cookie" => {
                    if let Some(c) = iter.next() {
                        cookie = Some(c);
                    }
                }
                _ => {
                    if !arg.starts_with('-') && url.is_empty() {
                        url = arg;
                    }
                }
            }
        }

        if url.is_empty() {
            return Err("未能解析出有效的 URL".to_string());
        }

        Ok(Self {
            url,
            method,
            cookie,
            headers,
            body,
        })
    }
}

#[derive(Debug, Clone)]
pub struct CurlConvertor {
    pub body_type: BodyType, // 请求体类型
    pub method: MethodType,  // 请求方法
    pub curl_init: CurlCommand,
}
/// curl转换代码结构体
impl CurlConvertor {
    pub fn new() -> Self {
        Self {
            body_type: BodyType::Unknown,
            method: MethodType::GET,
            curl_init: CurlCommand {
                url: String::new(),
                method: String::new(),
                cookie: None,
                headers: Vec::new(),
                body: None,
            },
        }
    }
    /// 通过解析 `CurlCommand` 构建 CurlPared 实例。
    ///
    /// - 根据请求体内容推断 [`BodyType`]：
    ///   - 包含 `"Content-Disposition"` 或 `"filename="` 判为 `Multipart`
    ///   - 包含 `=` 但不含 `{` 判为 `Form`
    ///   - 以 `{` 开头 判为 `Json`
    ///   - 否则为 `Binary`
    ///   - 如果没有 body 则为 `Unknown`
    ///
    /// - 根据请求方法推断 [`MethodType`]：仅支持 GET 和 POST，默认 GET。
    ///
    /// # 参数
    /// - `curl_cmd`: 从命令行解析得到的 CurlCommand
    ///
    /// # 返回
    /// - `Ok(Self)` 包含推断出的类型和原始命令
    /// - `Err(String)` 理论上不会出现，目前未使用错误路径
    ///
    /// # 示例
    /// ```rust
    /// let cmd = CurlCommand { method: "POST".to_string(), body: Some("a=1&b=2".to_string()), ... };
    /// let parsed = CurlPared::from_str(cmd)?;
    /// assert_eq!(parsed.body_type, BodyType::Form);
    /// ```
    pub fn from_str(self, mut curl_cmd: CurlCommand) -> Result<Self, String> {
        // 推断 BodyType
        let body_type = if let Some(ref body) = curl_cmd.body {
            if body.contains("Content-Disposition") || body.contains("filename=") {
                BodyType::Multipart
            } else if body.contains('=') && !body.contains('{') {
                BodyType::Form
            } else if body.trim_start().starts_with('{') {
                BodyType::Json
            } else {
                BodyType::Binary
            }
        } else {
            BodyType::Unknown
        };

        // 推断 MethodType
        if curl_cmd.body.is_some() {
            curl_cmd.method = String::from("post");
        } else {
            curl_cmd.method = String::from("get");
        };

        let method_type = match curl_cmd.method.to_uppercase().as_str() {
            "POST" => MethodType::POST,
            "GET" => MethodType::GET,

            _ => MethodType::GET,
        };

        Ok(Self {
            body_type,
            method: method_type,
            curl_init: curl_cmd,
        })
    }
    /// 将curl结构转换为python代码
    pub fn to_python(self) -> String {
        let mut code = String::new(); //代码字符串
        let mut args: Vec<String> = Vec::new();
        code.push_str("import requests\n");
        // 解析url，有参数带参数
        match UrlPared::init(&self.curl_init.url) {
            Ok(up) => {
                let text = up.to_python();
                code.push_str(&text);
                args.push("url=url".to_string());
                if text.contains("params =") {
                    args.push("params=params".to_string());
                }
            }
            Err(_) => (),
        }
        // 解析headers
        if !self.curl_init.headers.is_empty() {
            code.push_str("headers = {\n");
            self.curl_init
                .headers
                .iter()
                .map(|(k, v)| {
                    format!(
                        "    \"{k}\": \"{}\";\n",
                        v.replace("\\", "\\\\").replace("\"", "\\\"")
                    )
                })
                .collect::<Vec<String>>()
                .iter()
                .for_each(|c| code.push_str(c));
            code.push_str("    }\n");
            args.push("headers=headers".to_string());
        }
        // 解析cookie
        if let Some(ref cookies_str) = self.curl_init.cookie {
            if let Ok(cookies_store) = cookies_str.parse::<CookieStore>() {
                code.push_str(&cookies_store.to_python_dict());
                args.push("cookies=cookies".to_string());
            }
        }
        // 解析请求体
        if let Some(ref data) = self.curl_init.body {
            match self.body_type {
                BodyType::Unknown => {
                    code.push_str(format!("data = {}", data).as_str());
                    args.push("data=data".to_string());
                }
                BodyType::Json => {
                    code.push_str(format!("json_data = json.loads({})\n", data).as_str());
                    code.push_str("data = json.dumps(json_data, indent=2)\n");
                    args.push("data=data".to_string());
                }
                BodyType::Binary => {
                    code.push_str("# data is binary, handle with file or bytes if needed\n");
                    args.push("data=b'binary_data'".to_string());
                }
                BodyType::Form => {
                    code.push_str("data = {\n");
                    for (k, v) in self.extract_form().unwrap() {
                        code.push_str(format!("    {:?}: {:?},\n", k, v).as_str());
                    }
                    code.push_str("    }\n");
                    args.push("data=data".to_string());
                }
                BodyType::Multipart => {
                    code.push_str("files = {\n");
                    for (k, v) in self
                        .extract_data()
                        .as_ref()
                        .expect("Multipart格式解析不出来！")
                    {
                        println!("k{},v{}", k, v);
                        if v.contains("filename=") {
                            code.push_str(
                                format!("    {:?}: open('file_path', 'rb'),\n", k).as_str(),
                            );
                        } else {
                            code.push_str(format!("    {:?}: {:?},\n", k, v).as_str());
                        }
                    }

                    code.push_str("    }\n");
                    args.push("files=files".to_string());
                }
            };
        }

        code.push_str(format!("request.{}({})\n", self.method, args.join(", ")).as_str());

        code.push_str("print(res.text)\n");

        code
    }
    /// 转换为rust 请求代码
    pub fn to_rust(&self) -> String {
        let mut code = String::new();
        let temp = r#"
// maplit = "1.0.2"
// reqwest = { version = "0.12.22", features = ["json","cookies","multipart"] }
// serde = { version = "1.0.219", features = ["derive"] }
// serde_json = "1.0.141"
// tokio = { version = "1.46.1", features = ["full"] }
// url = "2.5.4"
use maplit::hashmap;
use reqwest;
use url::Url;
use reqwest::cookie::Jar;
use std::collections::HashMap;
use std::sync::Arc;
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {

    {{ $code }}

    let status = response.status();
    let body: serde_json::Value = response.json().await?;
    println!("Status: {}", status);
    println!("Response: {:#?}", body);

    Ok(())
}

            "#;
        let mut args: Vec<String> = Vec::new();
        // 处理url和请求参数
        match UrlPared::init(&self.curl_init.url) {
            Ok(up) => {
                let text = up.to_rust();
                code.push_str(&text);

                if text.contains("hashmap!") {
                    args.push(".query(&params)".to_string());
                }
            }
            Err(_) => (),
        }
        // 处理请求头
        if !self.curl_init.headers.is_empty() {
            code.push_str("    let raw_headers = hashmap! {\n");
            self.curl_init
                .headers
                .iter()
                .map(|(k, v)| {
                    format!(
                        "        \"{k}\"=> \"{}\",\n",
                        v.replace("\\", "\\\\").replace("\"", "\\\"")
                    )
                })
                .collect::<Vec<String>>()
                .iter()
                .for_each(|c| code.push_str(c));
            code.push_str("    };\n");
            code.push_str(
                r#"
        let mut headers = HeaderMap::new();
        for (k, v) in raw_headers {
                headers.insert(
                    HeaderName::from_bytes(k.as_bytes())?,
                    HeaderValue::from_str(v)?,
                );
        }
                "#,
            );
        }
        // 处理cookie
        if let Some(ref cookies_str) = self.curl_init.cookie {
            if let Ok(cookies_store) = cookies_str.parse::<CookieStore>() {
                code.push_str(&cookies_store.to_rust_hashmap());
                code.push_str(
                    r#"
        let jar = Jar::default();
            let url_parsed = Url::parse(url)?;
            for (k, v) in &cookies {
                jar.add_cookie_str(&format!("{k}={v}"), &url_parsed);
            }
                    "#,
                );
                args.push(
                    r#"
        .cookie_provider(Arc::new(jar))
        .default_headers(headers)
        "#
                    .to_string(),
                );
            }
        }

        // 处理data
        //
        if let Some(ref data) = self.curl_init.body {
            match self.body_type {
                BodyType::Unknown => {
                    code.push_str(format!("    let data = {}", data).as_str());
                    args.push(".body(data)".to_string());
                }
                BodyType::Json => {
                    code.push_str("    let data = ");
                    code.push_str(data);
                    code.push_str(";\n");
                    code.push_str(
                        "    let json_body: serde_json::Value = serde_json::from_str(data)?;\n",
                    );
                    args.push(".json(&json_body)".to_string());
                }
                BodyType::Binary => {
                    code.push_str(
                                    r#"    let data = b"binary_data"; // binary placeholder, replace with actual bytes "#,
                                );
                    args.push(".body(data.as_ref())".to_string());
                }
                BodyType::Form => {
                    code.push_str("    let data = hashmap! {\n");
                    for (k, v) in self.extract_form().unwrap_or_default() {
                        code.push_str(&format!("        {:?} => {:?},\n", k, v));
                    }
                    code.push_str("    };\n");
                    args.push(".form(&data)".to_string());
                }
                BodyType::Multipart => {
                    code.push_str("    let form = reqwest::multipart::Form::new()\n");
                    for (k, v) in self
                        .extract_data()
                        .as_ref()
                        .expect("Multipart格式解析不出来！")
                    {
                        if v.contains("filename=") {
                            code.push_str(&format!(
                                "        .file(\"{}\", \"file_path\")?\n",
                                k.replace("\"", "\\\"")
                            ));
                        } else {
                            code.push_str(&format!(
                                "        .text(\"{}\", \"{}\")\n",
                                k.replace("\"", "\\\""),
                                v.replace("\"", "\\\"")
                            ));
                        }
                    }
                    code.push_str("    ;\n");
                    args.push(".multipart(form)".to_string());
                }
            };
        }
        // 处理发起请求

        // 构建 client
        if args
            .iter()
            .any(|a| a.contains(".cookie_provider") || a.contains(".default_headers"))
        {
            code.push_str("    let client = reqwest::Client::builder()\n");
            for arg in &args {
                if arg.contains(".cookie_provider") || arg.contains(".default_headers") {
                    code.push_str(&format!("        {}\n", arg.trim()));
                }
            }
            code.push_str("        .build()?;\n");
        } else {
            code.push_str("    let client = reqwest::Client::new();\n");
        }

        code.push_str(&format!(
            "    let response = client.request(reqwest::Method::{}, url)\n",
            self.curl_init.method.to_uppercase()
        ));

        // 拼接参数调用链（headers、body、form、json、multipart、query...）
        for arg in args {
            if !arg.contains("cookie_provider") && !arg.contains("default_headers") {
                code.push_str(&format!("        {}\n", arg));
            }
        }

        code.push_str("        .send()\n        .await?;\n");

        // 插入请求代码到前面拼好的 code 中

        code = temp.replace("{{ $code }}", &code);

        code
    }

    pub fn extract_data(&self) -> Option<Vec<(String, String)>> {
        let data = self.curl_init.body.as_ref()?; // 如果为 None，直接返回 None

        let mut result: Vec<(String, String)> = Vec::new();
        let parts: Vec<_> = data
            .split("\\r\\n")
            .filter(|c| !c.trim().is_empty())
            .filter(|c| !c.contains("------"))
            .collect();
        let mut items = parts.iter().peekable();
        while let Some(header) = items.next() {
            if let Some(name_part) = header.split("name=\"").nth(1) {
                if let Some(field_id) = name_part.split("\"").next() {
                    let val = match items.peek() {
                        Some(v) => {
                            // 如果 peek 是不是 name 字段，就用它作为值
                            if v.contains("name=\"") {
                                "".to_string() // 下一个是键，不是值
                            } else {
                                items.next().unwrap_or(&"").to_string() // 消费并使用
                            }
                        }
                        None => "".to_string(), // 没有值了
                    };
                    result.push((field_id.to_string(), val));
                }
            }
        }

        Some(result)
    }

    pub fn extract_form(&self) -> Option<Vec<(String, String)>> {
        let data = self.curl_init.body.as_ref()?;
        Some(
            data.split("&")
                .map(|s| {
                    let mut parts = s.splitn(2, "=");
                    let key = parts.next().unwrap_or("").to_string();
                    let val = parts.next().unwrap_or("").to_string();
                    (key, val)
                })
                .collect(),
        )
    }
}
